﻿/*
 * @author rayzhang
 * @desc 页面路由
 */
#pragma once
#include <QVariantMap>
#include <QStackedWidget>
#include <QSharedPointer>
#include "event_dispatcher.h"
#include "../libflow_global.h"
using RouterView = QStackedWidget;

namespace flow
{

// 页面路由
// 路由应该封装成一个widget ?
class LIBFLOW_API PageRouter final : public EventDispatcher<QWidget*, const QVariantMap&>
{
    Q_OBJECT

public:
    class Future // Future
    {
        friend class PageRouter;

    public:
        ~Future() { _onValue = {}; }
        void then(const std::function<void(QVariant)>& onValue) { _onValue = onValue; }

    private:
        void complete(const QVariant& value) const
        {
            if (_onValue) {
                _onValue(value);
            }
        }

        std::function<void(QVariant)> _onValue;
    };

    struct PopParams
    {
        bool keepAlive;
        QVariant value;
        QString route; // 指定页面
        PopParams()
            : keepAlive(false) // 在这里初始化
        { }
    };

public:
    // 别名是为了可读
    using WidgetBuilder = Handler;

    explicit PageRouter(QObject* parent = nullptr)
        : EventDispatcher(parent)
    { }

    // 设置当前显示的内容，如果存在就显示，否则就创建一个显示
    QSharedPointer<Future> push(QString route, PayloadType args = {});
    // 返回上一个页面， 并设置当前页面是否驻留内存。此外，如果of传递的是RouterView，就直接弹出传入的RouterView的组件，否则就弹出自己。
    void pop(PopParams arguments = PopParams());
    // 当前页面弹出并压入指定页面
    QSharedPointer<PageRouter::Future> replace(const QString& route, PayloadType pushArgs = {}, PopParams popArgs = PopParams());

    bool dynamicDefine(const QString& route, PayloadType args);
    // 重定向
    void defineRedirect(const QString& from, const QString& to);
    void removeRedirect(const QString& from);

    PageRouter& of(QWidget* view);
    PageRouter& of(const QString& route);

    const QString& currentPath() const { return _currentRoute; }
    // 找到指定路由的页面
    QWidget* find(const QString& route) const;
    // 当前页面
    QWidget* currentWidget() const;

    // 拦截器
    void addPushNamedInterceptor(const RequestInterceptor& interceptor);

private:
    void push(QWidget* widget, int pos = -1) const;
    bool findParentRouterView();
    void popNamed(const QString& route, const PopParams& arguments);
    void popCurrent(const PopParams& arguments, QString& route);
    void afterPop(const QString& route, const PopParams& arguments = {});

    size_t viewId() const;
signals:
    // 路由改变事件
    void routeChanged(const QString& from, const QString& to);
    //  PageRouter& operator()(const QWidget* view) { return this->of(view); }
private:
    QWidget* _viewContainer = nullptr;
    RouterView* _view       = nullptr;
    QString _currentRoute;
    QList<RequestInterceptor> _pushNamedInterceptors;

    QMap<QString, QString> _redirectMap;

    QMap<size_t, QMap<QString, QSharedPointer<Future>>> _routePopValue; // <viewId, <route, future>>

    QMap<size_t, QMap<QString, QWidget*>> _routesView; //<viewId, <route, page>> 页面缓存
};
using PageRouterPtr = QSharedPointer<PageRouter>;
} // namespace flow